package cn.lingyangwl.agile.auth.service.impl;

import cn.lingyangwl.agile.auth.model.LockUser;
import cn.lingyangwl.agile.auth.model.rqrs.ConditionLockUserResp;
import cn.lingyangwl.agile.auth.oauth2.Authentication;
import cn.lingyangwl.agile.auth.oauth2.model.RegisteredClient;
import cn.lingyangwl.agile.auth.service.LoginUserService;
import cn.lingyangwl.agile.model.enums.AuthErrorEnum;
import cn.lingyangwl.framework.cache.core.service.CacheService;
import cn.lingyangwl.framework.tool.core.DateUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author shenguangyang
 */
@Service
public class LoginUserServiceImpl implements LoginUserService {
    @Resource
    private CacheService cacheService;

    @Override
    public LockUser getLockUser(String account, Authentication authentication) {
        RegisteredClient client = authentication.getClient();
        if (Objects.isNull(client) || !client.hasLimitLoginFail()) {
            return null;
        }
        // 获取到的是锁定的时间戳
        String lockUserKey = "lock_user::" + account + "_lock";
        return cacheService.opsForValue().get(lockUserKey);
    }

    @Override
    public void checkLockUser(String account, Authentication authentication) {
        LockUser lockUser = this.getLockUser(account, authentication);
        if (Objects.nonNull(lockUser)) {
            String unlockTime = DateUtils.distance(System.currentTimeMillis(), lockUser.getUnLockTimestamp(), true);
            throw new BizException(AuthErrorEnum.LOGIN_LOCKED, unlockTime);
        }
    }

    @Override
    public ConditionLockUserResp conditionLockUser(String account, Authentication authentication) {
        ConditionLockUserResp.ConditionLockUserRespBuilder builderResp = ConditionLockUserResp.builder();
        builderResp.locked(false).hasLimitLoginFail(true);

        RegisteredClient clientDetails = authentication.getClient();
        if (!clientDetails.hasLimitLoginFail()) {
            builderResp.hasLimitLoginFail(false);
            return builderResp.build();
        }

        String lockUserKey = "lock_user::" + account + "_lock";
        long loginFail = cacheService.opsForValue().incrementBy("lock_user::" + account + "_login_fail", 1);
        if (loginFail % clientDetails.getLoginFailCount() == 0) {
            int lockCount = (int) (loginFail / clientDetails.getLoginFailCount());
            // 单位为秒
            int lockTime = clientDetails.getLockInterval() * clientDetails.getLockMultiplier() * lockCount;
            LockUser lockUser = LockUser.builder().lockCount(lockCount).lockTime(lockTime)
                    .unLockTimestamp(System.currentTimeMillis() + lockTime * 1000L).build();
            // 设置锁定数据
            cacheService.opsForValue().setEx(lockUserKey, lockUser, lockTime + 2, TimeUnit.SECONDS);
            builderResp.locked(true).unLockTimestamp(lockUser.getUnLockTimestamp());
        }
        int surplusLockedCount = Long.valueOf(clientDetails.getLoginFailCount() - loginFail % clientDetails.getLoginFailCount())
                .intValue();
        builderResp.surplusLockedCount(surplusLockedCount);
        return builderResp.build();
    }

    @Override
    public void unLockUser(String account, RegisteredClient client) {
        if (!client.hasLimitLoginFail()) {
            return;
        }
        cacheService.opsForKey().delete("lock_user::" + account + "_login_fail");
        cacheService.opsForKey().delete("lock_user::" + account + "_lock");
    }
}
